package myJs.browse

import myJs.Implicits._
import myJs.api.Api
import myJs.cps.BootstrapTableCp.Column
import myJs.cps._
import myJs.myPkg._
import myJs.search.circDetail.CircDetail
import myJs.search.detail.Detail
import myJs.tool.Pojo._
import myJs.tool.Tool
import org.scalajs.dom.Event
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._
import slinky.core.{FunctionalComponent, SyntheticEvent}
import slinky.core.annotations.react
import slinky.core.facade.Hooks._
import slinky.web.html._
import upickle.default._

import scala.collection.immutable.SeqMap
import scala.scalajs.js

/**
 * Created by yz on 21/1/2022
 */
@react object CRnaCp {

  case class Props(geneType: String)

  val component = FunctionalComponent[Props] { props =>

    val speciesMap = List("Hsa", "Mmu").optionMap
    val initSpeciesCheckedMap = speciesMap.map { case (k, v) =>
      (k, false)
    }
    val circBaseIdMap = List("Yes", "No").optionMap
    val initCirBaseIdCheckedMap = circBaseIdMap.map { case (k, v) =>
      (k, false)
    }
    val (datas, setDatas) = useState(List.empty[ujson.Obj])
    val (columns, setColumns) = useState(List.empty[Column])
    val (speciesCheckedMap, setSpeciesCheckedMap) = useState(initSpeciesCheckedMap)
    val (cirBaseIdCheckedMap, setCirBaseIdCheckedMap) = useState(initCirBaseIdCheckedMap)
    val (refresh, setRefresh) = useState(false)
    val initGeneSymbol = "both"
    val (geneSymbol, setGeneSymbol) = useState(initGeneSymbol)
    val initGeneName = ""
    val (geneName, setGeneName) = useState(initGeneName)
    val (geneNameShow, setGeneNameShow) = useState(true)
    val (chrMap, setChrMap) = useState(SeqMap[String, String]())
    val initChr = "All"
    val (chr, setChr) = useState(initChr)
    val initStart = ""
    val (start, setStart) = useState(initStart)
    val initEnd = ""
    val (end, setEnd) = useState(initEnd)
    val (seShow, setSeShow) = useState(false)

    object FTool {

      def refreshChrMap = {
        Api.browseCirc.allChr.map { response =>
          val data = "All" :: response
          setChrMap(data.optionMap)
        }
      }

      def geneNameChange = (v: String) => {
        setGeneName(v)
      }

      def startChange = (v: String) => {
        setStart(v)
      }

      def endChange = (v: String) => {
        setEnd(v)
      }

      def chrChange = (v: String) => {
        setChr(v)
      }

      def geneSymbolChange = (v: String) => {
        setGeneSymbol(v)
      }

      def speciesCheckedMapChange = (v: SeqMap[String, Boolean]) => {
        setSpeciesCheckedMap(v)
      }

      def circBaseIdCheckedMapChange = (v: SeqMap[String, Boolean]) => {
        setCirBaseIdCheckedMap(v)
      }

      def search = () => {
        setRefresh(true)
      }

      def refreshColumns = () => {
        val select2Keys = List("species", "geneType")
        val data = ujson.Obj(
          "keys" -> select2Keys
        )
        val dataStr = write(data)
        Api.getSelect2Values(dataStr).map { rs =>
          val fieldOptionMap = rs.map { case (k, v) =>
            val inputName = k
            val data = v.toJArS.toList
            (inputName, data)
          }.toList.toSeqMap

          val map = SeqMap(
            "circId" -> "circID",
            "circBase" -> "circBase ID",
            "species" -> "Species",
            "position" -> "Position",
            "strand" -> "Strand",
            "geneSymbol" -> "Gene Symbol",
            "geneType" -> "Gene Type",
            "allMean" -> "All Mean",
            "allFreq" -> "All Freq",
            "fetalMean" -> "Fetal Mean",
            "fetalFreq" -> "Fetal Freq",
            "normalMean" -> "Normal Mean",
            "normalFreq" -> "Normal Freq",
            "nafldMean" -> "NAFLD Mean",
            "nafldFreq" -> "NAFLD Freq",
            "aldMean" -> "ALD Mean",
            "aldFreq" -> "ALD Freq",
            "vhMean" -> "Viral Hepatitis Mean",
            "vhFreq" -> "Viral Hepatitis Freq",
            "fibrosisMean" -> "Fibrosis Mean",
            "fibrosisFreq" -> "Fibrosis Freq",
            "cirrhosisMean" -> "Cirrhosis Mean",
            "cirrhosisFreq" -> "Cirrhosis Freq",
            "dnMean" -> "Dysplastic Nodule Mean",
            "dnFreq" -> "Dysplastic Nodule Freq",
            "hccMean" -> "HCC Mean",
            "hccFreq" -> "HCC Freq",
            "mixedMean" -> "Mixed HCC-ICC Mean",
            "mixedFreq" -> "Mixed HCC-ICC Freq",
            "iccMean" -> "ICC Mean",
            "iccFreq" -> "ICC Freq",
            "hbMean" -> "HB Mean",
            "hbFreq" -> "HB Freq",
          )
          val basicColumns = map.map { case (k, v) =>
            val searchKind = k match {
              case x if (x.endsWith("Median") || x.endsWith("Freq")) => DoubleSearch
              case x if select2Keys.contains(x) => CheckboxSearch
              case _ => TextSearch
            }
            val title = v match {
              case _ => v
            }
            val operable = k match {
              case "species" => false
              case _ => true
            }
            val fmt = FTool.tbFmt(k)
            val comVF = FTool.comVFmt(v)
            val optionMap = searchKind match {
              case CheckboxSearch => fieldOptionMap(k).optionMap
              case _ => SeqMap[String, String]()
            }
            val defaultValue = v match {
              case "Gene Type" => props.geneType
              case _ => ""
            }
            Column(field = k, title = title, operable = operable, searchKind = searchKind, formatter = fmt,
              comVF = comVF, optionMap = optionMap, defaultValue = defaultValue)
          }.toList
          setColumns(basicColumns)
        }
      }

      def tbFmt(field: String) = (v: ujson.Value, row: ujson.Obj) => {
        field match {
          case "geneSymbol" =>
            val url = s"#${Detail.absolutePath}"
            a(target := "_blank", href := s"${url}?geneName=${v.str}&species=${row("species").str}", s"${v.str}")()
          case "circBase" =>
            val url = s"http://www.circbase.org/cgi-bin/singlerecord.cgi?id=${v.str}"
            a(target := "_blank", href := s"${url}", s"${v.str}")()
          case "circId" =>
            val url = s"${CircDetail.absolutePath}"
            a(target := "_blank", href := s"${url}?circId=${v.str.encodeURI}&species=${row("species").str}", s"${v.str}")()
          case _ => val vStr = v.myStr
            span(vStr)()
        }
      }

      def comVFmt(fileTitle: String) = (v: ujson.Value, row: ujson.Obj) => {
        fileTitle match {
          case _ => v.myStr
        }
      }

      def ajaxRequest = (limit: Int, offset: Int,
                         searchMap: SeqMap[String, SearchData], sortDataOp: Option[SortData], allSearch: String) => {
        val options = Tool.layerOptions.copy(shade = List("0.1", "#fff"))
        val index = layer.load(0, options)
        val trueSortObj = if (sortDataOp.isEmpty) {
          ujson.Obj()
        } else {
          val sortData = sortDataOp.get
          ujson.Obj("sort" -> ujson.Obj(
            "field" -> sortData.field,
            "kind" -> sortData.kind,
            "order" -> sortData.order,
          ))
        }
        val searchs = searchMap.map { case (k, searchData) =>
          searchData match {
            case TextSearchData(searchType, text) =>
              ujson.Obj(
                "name" -> k,
                "kind" -> "text",
                "searchType" -> searchType,
                "value" -> text,
              )
            case NumericSearchData(min, max, kind) =>
              ujson.Obj(
                "name" -> k,
                "kind" -> kind,
                "min" -> Tool.dbFmt(min),
                "max" -> Tool.dbFmt(max),
              )
            case CheckboxSearchData(values) =>
              ujson.Obj(
                "name" -> k,
                "kind" -> "checkbox",
                "value" -> values,
              )
          }
        }.toList
        val speciesSearch = Tool.checkedMap2Search("species", speciesCheckedMap)
        val circBaseIdSearch = Tool.checkedMap2Search("circBase", cirBaseIdCheckedMap)
        val geneSymbolSearch = ujson.Obj(
          "name" -> "geneSymbol",
          "kind" -> "checkbox",
          "value" -> List(geneSymbol),
        )
        val geneNameSearch = if (geneNameShow) {
          ujson.Obj(
            "name" -> "geneSymbol",
            "kind" -> "text",
            "searchType" -> "like",
            "value" -> geneName,
          )
        } else {
          ujson.Obj()
        }
        val chrSearch = if (chr == "All" || chrMap.isEmpty) {
          ujson.Obj()
        } else {
          ujson.Obj(
            "name" -> "chr",
            "kind" -> "checkbox",
            "value" -> List(chr),
          )
        }
        val startSearch = if (seShow) {
          ujson.Obj(
            "name" -> "start",
            "kind" -> "int",
            "min" -> Tool.dbFmt(start),
            "max" -> Tool.dbFmt(""),
          )
        } else ujson.Obj()
        val endSearch = if (seShow) {
          ujson.Obj(
            "name" -> "end",
            "kind" -> "int",
            "min" -> Tool.dbFmt(""),
            "max" -> Tool.dbFmt(end),
          )
        } else ujson.Obj()
        val formSearchs = List(
          speciesSearch, circBaseIdSearch, geneSymbolSearch, geneNameSearch, chrSearch, startSearch, endSearch
        ).filter { obj =>
          obj.value.nonEmpty
        }
        val trueSearchObj = ujson.Obj("search" -> (searchs ::: formSearchs))
        val obj = ujson.Obj(
          "limit" -> limit,
          "offset" -> offset,
          "allSearch" -> allSearch
        ) ++ trueSortObj ++ trueSearchObj
        val dataStr = write(obj)
        Api.browseCirc.allByServer(dataStr).map { obj =>
          layer.close(index)
          obj
        }

      }

      def refreshChange = (v: Boolean) => {
        setRefresh(v)
      }

      def reset = () => {
        setSpeciesCheckedMap(initSpeciesCheckedMap)
        setCirBaseIdCheckedMap(initCirBaseIdCheckedMap)
        setGeneSymbol(initGeneSymbol)
        setGeneName(initGeneName)
        setChr(initChr)
        setStart(initStart)
        setEnd(initEnd)
      }

    }

    useEffect(() => {
      FTool.refreshColumns()
    }, List()
    )

    useEffect(() => {
      setGeneNameShow(geneSymbol != "NA")
    }, List(geneSymbol)
    )

    useEffect(() => {
      setSeShow(chr != "All")
    }, List(chr)
    )

    useEffect(() => {
      FTool.refreshChrMap
    }, List()
    )

    val exportDatas = List(
      ExportData("TXT", href = s"${Api.apiUrl}/gepLiver/tool/downloadFile?fileName=Browse_circ.txt")
    )

    div(

      form(className := "form-horizontal", id := "form",

        div(className := "myEachGroup form-group",
          label(className := "control-label col-sm-2", s"Species:"),
          div(className := "col-sm-10",
            PureCheckboxCp(checkedMap = speciesCheckedMap, checkedMapChange = FTool.speciesCheckedMapChange)
          )
        ),

        div(className := "myEachGroup form-group",
          label(className := "control-label col-sm-2", s"circBase ID:"),
          div(className := "col-sm-10",
            PureCheckboxCp(checkedMap = cirBaseIdCheckedMap, checkedMapChange = FTool.circBaseIdCheckedMapChange)
          )
        ),

        div(className := "myEachGroup form-group",
          label(className := "control-label col-sm-2", s"Gene Symbol:"),
          div(className := "col-sm-3",
            {
              val optionMap = List("both", "exist", "NA").optionMap
              PureSelectCp(optionMap = optionMap, value = geneSymbol, onChange = FTool.geneSymbolChange)
            }
          ),
          div(style := Style(display = Tool.b2Display(geneNameShow)), className := "col-sm-3",
            PureTypeaheadInputCp(placeHolder = "gene symbol", value = geneName, onChange = FTool.geneNameChange,
              name = "geneName")
          )
        ),

        div(className := "myEachGroup form-group",
          label(className := "control-label col-sm-2", s"Region:"),
          div(className := "col-sm-3",
            PureSelectCp(optionMap = chrMap, value = chr, onChange = FTool.chrChange)
          ),
          div(style := Style(display = Tool.b2Display(seShow)),
            div(className := "col-sm-3",
              PureInputCp(placeHolder = "start", value = start, onChange = FTool.startChange)
            ),
            div(className := "col-sm-3",
              PureInputCp(placeHolder = "end", value = end, onChange = FTool.endChange)
            )
          )

        ),

        div(className := "form-group",
          div(className := "actions col-sm-offset-2 col-sm-3",
            button(style := Style(width = "95%"), `type` := "button", className := "btn btn-primary myBtn",
              onClick := FTool.search,
              s" Search"
              ,
            ),
          ),
          div(className := "actions col-sm-3",
            button(style := Style(width = "95%"), `type` := "button", className := "btn btn-primary myBtn",
              onClick := FTool.reset,
              s" Reset",
            ),
          )
        ),

      ),

      hr(),

      div(style := Style(),
        BootstrapTableCp(columns = columns, datas = datas, pageList = List(10, 25, 50), pageSize = 10,
          sidePagination = "server", ajax = FTool.ajaxRequest, selectColumnEnabled = true, refresh = refresh,
          refreshChange = FTool.refreshChange, exportData = exportDatas, showExport = true, search = true)
      ),
    )


  }

  object STool {

  }

}
